﻿using Hue_Demo_PCL.Helpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Hue_Demo_PCL.Models
{
    /// <summary>
    /// a bindable object to represent the Hue light
    ///    along with properties that can be interfaced
    ///    with in a WinPhone or Windows app
    /// </summary>
    [DataContract]
    public class HueLight : INotifyPropertyChanged
    {
        public HueLight() { }

        public HueLight(LightState ls, int index)
        {
            Index = index;
            IsOn = ls.IsOn;
            Brightness = ls.Brightness;
            Hue = ls.Hue;
            Saturation = ls.Saturation;
            //UpdateRGB();
            HueToRGB();
        }

        #region Index (int)
        private int _index = -1;
        public int Index
        {
            get { return _index; }
            set
            {
                _index = value;
                NotifyPropertyChanged("Index");
            }
        }
        #endregion

        #region IsOn (bool)
        private bool _isOn = true;
        [DataMember(Name = "on")]
        public bool IsOn
        {
            get { return _isOn; }
            set
            {
                _isOn = value;
                NotifyPropertyChanged("IsOn");
            }
        }
        #endregion

        #region Hue (int)
        private int _hue = 0;
        [DataMember(Name = "hue")]
        public int Hue
        {
            get { return _hue; }
            set
            {
                _hue = value;
                NotifyPropertyChanged("Hue");
            }
        }
        #endregion

        #region Saturation (int)
        private int _saturation = 0;
        [DataMember(Name = "sat")]
        public int Saturation
        {
            get { return _saturation; }
            set
            {
                _saturation = value;
                NotifyPropertyChanged("Saturation");
            }
        }
        #endregion

        #region Brightness (int)
        private int _brightNess = 254;
        [DataMember(Name = "bri")]
        public int Brightness
        {
            get { return _brightNess; }
            set
            {
                _brightNess = value;
                NotifyPropertyChanged("Brightness");
            }
        }
        #endregion

        #region Red (int)
        private int _red = 0;
        public int Red
        {
            get { return _red; }
            set
            {
                _red = value;
                NotifyPropertyChanged("Red");
                UpdateHueSat();
            }
        }
        #endregion

        #region Green (int)
        private int _green = 0;
        public int Green
        {
            get { return _green; }
            set
            {
                _green = value;
                NotifyPropertyChanged("Green");
                UpdateHueSat();
            }
        }
        #endregion

        #region Blue (int)
        private int _blue = 0;
        public int Blue
        {
            get { return _blue; }
            set
            {
                _blue = value;
                NotifyPropertyChanged("Blue");
                UpdateHueSat();
            }
        }
        #endregion

        // Set the hue and saturation based on the current
        //   RGB values and raise the NotifyProperty events
        public void UpdateHueSat()
        {
            // hue calculation derived from Coding4Fun toolkit
            if (Red == Green && Green == Blue)
                _hue = 0;

            var r = Red / 255f;
            var g = Green / 255f;
            var b = Blue / 255f;

            float tempHue;

            var min = Numbers.Min(r, g, b);
			var max = Numbers.Max(r, g, b);

            var delta = max - min;

			if (r.AlmostEquals(max))
                tempHue = (g - b) / delta; // between yellow & magenta
            else if (g.AlmostEquals(max))
                tempHue = 2 + (b - r) / delta; // between cyan & yellow
            else
                tempHue = 4 + (r - g) / delta; // between magenta & cyan

            tempHue *= 60; // degrees

            if (tempHue < 0)
                tempHue += 360;

            _hue = (int)(tempHue * 182.04);

            // sat calcluation derived from Coding4Fun Toolkit
            var r2 = Red / 255f;
            var g2 = Green / 255f;
            var b2 = Blue / 255f;

            var min2 = Numbers.Min(r2, g2, b2);
            var max2 = Numbers.Max(r2, g2, b2);
            float tempSat;

            if (max2.AlmostEquals(min2))
                tempSat = 0;

            tempSat = (max.AlmostEquals(0f)) ? 0f : 1f - (1f * min / max);

            _saturation = (int)(tempSat * 245);

            NotifyPropertyChanged("Hue");
            NotifyPropertyChanged("Saturation");

            
        }

        // Set the RGB values based on the hue and saturation
        //   values collected from the lights.
        public void HueToRGB()
        {
            float tempHue = (float)(Hue / 182.04);
            float tempSat = (float)(Saturation / 245.0);
            // from http://stackoverflow.com/questions/359612/how-to-change-rgb-color-to-hsv
            int hi = Convert.ToInt32(Math.Floor(tempHue / 60) % 6);
            double f = tempHue / 60 - Math.Floor(tempHue / 60);
            int value = 255;
            int p = Convert.ToInt32(value * (1 - tempSat));
            int q = Convert.ToInt32(value * (1 - f * tempSat));
            int t = Convert.ToInt32(value * (1 - (1 - f) * tempSat));
            if (hi == 0)
            {
                Red = value;
                Green = t;
                Blue = p;
            }
            else if (hi == 1)
            {
                Red = q;
                Green = value;
                Blue = p;
            }
            else if (hi == 2)
            {
                Red = p;
                Green = value;
                Blue = t;
            }
            else if (hi == 3)
            {
                Red = p;
                Green = q;
                Blue = value;
            }
            else if (hi == 4)
            {
                Red = t;
                Green = p;
                Blue = value;
            }
            else
            {
                Red = value;
                Green = p;
                Blue = q;
            }

            //NotifyPropertyChanged("Red");
            //NotifyPropertyChanged("Green");
            //NotifyPropertyChanged("Blue");
        }
        
        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }     
    }
}
